//
// Created by LiuYou on 2021/10/29.
//

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <csignal>


static const int THREAD_NUM = 4;

static bool isLoop = true;

//static pthread_mutex_t MUTEX[THREAD_NUM] = {PTHREAD_MUTEX_INITIALIZER};
//static pthread_mutex_t mutex[THREAD_NUM];
static pthread_mutex_t MUTEX = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t COND = PTHREAD_COND_INITIALIZER;

static int num;


static int next(int num) {
    if (num + 1 == THREAD_NUM) {
        return 0;
    }
    return num + 1;
}


/*
 *todo 笔记: 使用死锁, 其实就是加上了顺序, 本来是乱序的,
 * 加上死锁后就有顺序了。
 */
int main(int argc, char** argv) {

    struct sigaction sa{};
    sa.sa_handler = [](int signal) {
        isLoop = false;
    };
    sa.sa_flags = 0;
    sigemptyset( &sa.sa_mask );

    sigaction( SIGALRM, &sa, nullptr );
    alarm( 5 );

    pthread_t tidArray[THREAD_NUM]{};
    for (int i = 0; i < THREAD_NUM; ++i) {
        int* pInt = new int( i );
        int errNum = pthread_create(
                tidArray + i, nullptr,
                [](void* args) -> void* {

                    int ch = 'a' + *static_cast<char*>(args);

                    // 线程编号。0 1 2 3
                    int n = *static_cast<int*>(args);

                    while (isLoop) {
//                        pthread_mutex_lock( mutex + (*(int*) args));
                        pthread_mutex_lock( &MUTEX );

                        while (num != n) {
                            pthread_cond_wait( &COND, &MUTEX );
                        }

                        write( STDOUT_FILENO, &ch, 1 );
                        num = next( num );
                        pthread_cond_broadcast( &COND );
                        pthread_mutex_unlock( &MUTEX );
//                        pthread_mutex_unlock( mutex + next( *(int*) args ));
                    }

                    pthread_exit( args );
                },
                pInt );
        if (errNum != 0) {
            fprintf( stderr, "pthread_create(): %s.\n", strerror( errNum ));
            return 1;
        }
    }


    for (int i = 0; i < THREAD_NUM; ++i) {
        void* threadReturn{};
        pthread_join( tidArray[i], &threadReturn );
        delete static_cast<int*>(threadReturn);
    }


    pthread_mutex_destroy( &MUTEX );
    pthread_cond_destroy( &COND );


    return 0;
}
